﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.DB;
using YArchitech.ProgressBar;
using YJKRevitBase.WinForm;
using YJKOpeningCommon.DataEnum;
using YJKOpeningCommon.DbOpening;
using YJKOpeningCommon.OpeningEX;
using YJKOpeningCommon.OpeningProfile;
using YJKOpeningCommon.Public;
using YJKOpeningDesignInput.Public;
using YJKGeometryFuncs;

namespace YJKOpeningDesignInput.DbOpeningCreatorFactory
{
	internal class DbEquipWallOpeningCreatorFactory : DbOpeningBaseCreatorFactory
	{
        public DbEquipWallOpeningCreatorFactory(ref List<Document> lstDoc, WindowHandle handle, Dictionary<string, int> dicOpeningProfileData)
            : base(ref lstDoc, handle, dicOpeningProfileData)
		{
			Document doc = lstDoc[0];
			this.m_lstReLinkIns = CommonInterface.GetLinkRevitIns(doc);
		}

		public override bool CreateDbOpening(MEPData mepData, ref LinkedList<DbOpeningBase> lstDbOpening)
		{
			return this.GetOpeningDataByEquip(mepData.m_dictionaryEquip, mepData.m_lstInfos, ref lstDbOpening);
		}

		private bool GetOpeningDataByEquip(Dictionary<FamilyInstance, StructFiBindingData> lstEquip, List<YJKOpeningDesignInput.Public.PointSort> lstInfos, ref LinkedList<DbOpeningBase> lstDbopening)
		{
			ProgressBarForm progressBarForm = new ProgressBarForm(lstEquip.Count * this.m_lstDoc.Count, ProgressBarStyle.Blocks, true);
			bool result;
			try
			{
				progressBarForm.Text = "墙上设备碰撞检测";
				progressBarForm.ShowInTaskbar = false;
				progressBarForm.Show(this.m_hWndRevit);
				foreach (KeyValuePair<FamilyInstance, StructFiBindingData> dic in lstEquip)
				{
					FamilyInstance key = dic.Key;
					EEquipType equipType = dic.Value.EquipType;
					RevitLinkInstance revitLinkIns = dic.Value.RevitLinkIns;
					this.GetOpeningDataByEquip(this.m_lstDoc[0], dic, lstInfos, ref lstDbopening);
					progressBarForm.RefreshProgressBar();
					if (progressBarForm.m_stopTag)
					{
						return false;
					}
					foreach (RevitLinkInstance revitLinkInstance in this.m_lstReLinkIns)
					{
						Document linkDocument = revitLinkInstance.GetLinkDocument();
						if (linkDocument != null)
						{
							this.GetOpeningDataByEquip(linkDocument, dic, lstInfos, ref lstDbopening);
							progressBarForm.RefreshProgressBar();
							if (progressBarForm.m_stopTag)
							{
								return false;
							}
						}
					}
				}
				progressBarForm.Dispose();
				result = true;
			}
			catch (Exception ex)
			{
				progressBarForm.Dispose();
				ExceptionLog.WriteLog(ex.Message, true);
				result = false;
			}
			return result;
		}

		private void GetOpeningDataByEquip(Autodesk.Revit.DB.Document doc, KeyValuePair<FamilyInstance, StructFiBindingData> dic, List<YJKOpeningDesignInput.Public.PointSort> lstInfos, ref LinkedList<DbOpeningBase> lstDbopening)
		{
			Wall wall = null;
			OpeningData openingData = new OpeningData();
			XYZ equipCenterPt = null;
			double equipMinZ = 0.0;
			if (!Interface.GetAllIntersectSubjectByEquip(dic, ref wall, this.m_lstDoc[0], doc, ref openingData, ref equipCenterPt, ref equipMinZ))
			{
				return;
			}
			if (wall == null)
			{
				return;
			}
			if ((int)wall.WallType.Kind == 2 || (int)wall.WallType.Kind == 1)
			{
				return;
			}
			this.TraveAllWall(ref wall, dic, ref lstDbopening, ref openingData, equipCenterPt, equipMinZ, lstInfos);
		}

		private bool TraveAllWall(ref Wall wall, KeyValuePair<FamilyInstance, StructFiBindingData> dic, ref LinkedList<DbOpeningBase> lstOpening, ref OpeningData openingData, XYZ equipCenterPt, double equipMinZ, List<YJKOpeningDesignInput.Public.PointSort> lstInfos)
		{
			FamilyInstance key = dic.Key;
			EEquipType equipType = dic.Value.EquipType;
			DbOpeningBase dbOpeningBase = new DbEquipRectWallOpening();
			if (!Interface.GetOpeningDatasByEquip(ref dbOpeningBase, ref openingData, wall, key, equipCenterPt, equipMinZ, equipType, lstInfos))
			{
				return false;
			}
			openingData.m_extendDist = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["RectOpeningOutSize"]));
			openingData.m_tolerance = AssistFunc.mmToFeet(Convert.ToDouble(this.m_dicOpeningProfileData["CompositeTolerance"]));
			OpeningProfileBase openingProfileBase = new OpeningProfileEquipRect();
			Interface.SetOpeningProfile(ref openingProfileBase, openingData);
			OpeningProfileEquipRect openingProfileEquipRect = openingProfileBase as OpeningProfileEquipRect;
			openingProfileEquipRect.m_dHeight = openingData.m_cutHeight;
			openingProfileEquipRect.m_dThickness = openingData.m_cutWidth;
			openingProfileEquipRect.m_dWidth = openingData.m_cutLength;
			Interface.SetOpeningData2Opening(openingData, ref dbOpeningBase, openingProfileBase);
			Transform transform = null;
			if (dic.Value.RevitLinkIns != null)
			{
				transform = dic.Value.RevitLinkIns.GetTotalTransform();
			}
			if (this.IsHavingOpening(openingData, transform))
			{
				return false;
			}
			if (Geometry.LessThan(0.0032808398950131233, dbOpeningBase.m_profile.m_dPenetrationThickness))
			{
				lstOpening.AddLast(dbOpeningBase);
			}
			return true;
		}

		private bool IsHavingOpening(OpeningData openingData, Transform transform)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			this.GetNewOpeningBoundingBox(openingData, ref xyz, ref xyz2);
			if (transform != null)
			{
				xyz = transform.OfPoint(xyz);
				xyz2 = transform.OfPoint(xyz2);
			}
			Outline outline = new Outline(xyz, xyz2);
			XYZ openingMinPt = null;
			XYZ openingMaxPt = null;
			return this.GetOutLineIntersectOpening(outline, ref openingMinPt, ref openingMaxPt) && this.IsHavingOpening(openingMinPt, openingMaxPt, xyz, xyz2);
		}

		private bool IsHavingOpening(XYZ openingMinPt, XYZ openingMaxPt, XYZ newOpeningMinPt, XYZ newOpeningMaxPt)
		{
			double eps = 0.0001;
			return !Geometry.LessThan(newOpeningMinPt.X, openingMinPt.X, eps) && !Geometry.LessThan(openingMaxPt.X, newOpeningMaxPt.X, eps) && !Geometry.LessThan(newOpeningMinPt.Y, openingMinPt.Y, eps) && !Geometry.LessThan(openingMaxPt.Y, newOpeningMaxPt.Y, eps) && !Geometry.LessThan(newOpeningMinPt.Z, openingMinPt.Z, eps) && !Geometry.LessThan(openingMaxPt.Z, newOpeningMaxPt.Z, eps);
		}

		private bool GetOutLineIntersectOpening(Outline outline, ref XYZ minPt, ref XYZ maxPt)
		{
			BoundingBoxIntersectsFilter boundingBoxIntersectsFilter = new BoundingBoxIntersectsFilter(outline);
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_lstDoc[0]);
			filteredElementCollector.WherePasses(boundingBoxIntersectsFilter).OfCategory(BuiltInCategory.OST_GenericModel).WhereElementIsNotElementType();
			foreach (Element element in filteredElementCollector)
			{
				if (element is FamilyInstance && OpeningXData.IsIncludeSchema(element))
				{
					FamilyInstance familyInstance = element as FamilyInstance;
					minPt = familyInstance.get_BoundingBox(null).Min;
					maxPt = familyInstance.get_BoundingBox(null).Max;
					return true;
				}
			}
			foreach (RevitLinkInstance revitLinkInstance in this.m_lstReLinkIns)
			{
				Document linkDocument = revitLinkInstance.GetLinkDocument();
				if (linkDocument != null)
				{
					FilteredElementCollector filteredElementCollector2 = new FilteredElementCollector(linkDocument);
					filteredElementCollector2.WherePasses(boundingBoxIntersectsFilter).OfCategory(BuiltInCategory.OST_GenericModel).WhereElementIsNotElementType();
					foreach (Element element2 in filteredElementCollector2)
					{
						if (element2 is FamilyInstance && OpeningXData.IsIncludeSchema(element2))
						{
							FamilyInstance familyInstance2 = element2 as FamilyInstance;
							minPt = familyInstance2.get_BoundingBox(null).Min;
							maxPt = familyInstance2.get_BoundingBox(null).Max;
							Transform totalTransform = revitLinkInstance.GetTotalTransform();
							if (totalTransform != null)
							{
								minPt = totalTransform.OfPoint(minPt);
								maxPt = totalTransform.OfPoint(maxPt);
								return true;
							}
						}
					}
				}
			}
			return false;
		}

		private void GetNewOpeningBoundingBox(OpeningData openingData, ref XYZ minPt, ref XYZ maxPt)
		{
			double extendDist = openingData.m_extendDist;
			double num = Math.Abs(openingData.m_hostWidth / 2.0 - openingData.m_penetrationThickness);
			XYZ xyz = XYZ.BasisZ.CrossProduct(openingData.m_directionCutObj).Normalize();
			XYZ xyz2;
			if (Geometry.Lessthan_Or_Equal(openingData.m_penetrationThickness, openingData.m_hostWidth / 2.0))
			{
				xyz2 = openingData.m_position + openingData.m_openingDirection.Normalize() * num + xyz * (openingData.m_cutLength / 2.0 + extendDist);
			}
			else
			{
				xyz2 = openingData.m_position + openingData.m_openingDirection.Negate().Normalize() * num + xyz * (openingData.m_cutLength / 2.0 + extendDist);
			}
			XYZ item = xyz2 + xyz.Negate() * (2.0 * extendDist + openingData.m_cutLength);
			XYZ item2 = openingData.m_position + openingData.m_openingDirection.Normalize() * openingData.m_hostWidth / 2.0 + xyz.Negate() * (openingData.m_cutLength / 2.0 + extendDist);
			XYZ item3 = openingData.m_position + openingData.m_openingDirection.Normalize() * openingData.m_hostWidth / 2.0 + xyz * (openingData.m_cutLength / 2.0 + extendDist);
			CommonInterface.GetMinMaxVal(new List<XYZ>
			{
				xyz2,
				item,
				item2,
				item3
			}, ref minPt, ref maxPt);
			minPt = new XYZ(minPt.X, minPt.Y, minPt.Z - extendDist);
			maxPt = new XYZ(maxPt.X, maxPt.Y, maxPt.Z + openingData.m_cutHeight + extendDist);
		}

		private List<RevitLinkInstance> m_lstReLinkIns;
	}
}
